﻿using CommonLib.Attr;
using CommonLib.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace CommonLib.Base;

public abstract class BaseCodeEntity
{
    public bool IsDelete { get; set; } = false;

    private int CodeIndexLevel;

    public string EndComment { get; set; } = string.Empty;

    public BaseCodeEntity? PreEntity { get; set; }

    public BaseCodeEntity? NextEntity { get; set; }

    public BaseCodeEntity? ParentEntity { get; set; }

    private readonly Dictionary<BaseCodeEntity, ChildrenBean> ChildrenCode = new();

    protected string ConvertName => $"{GetType().Name.Replace("CodeEntity", "Convert")}";

    protected BaseConvert? Convert { get; set; }

    public BaseCodeEntity()
    {
        var assembly = Assembly.Load(ConstUtil.After);
        var type = assembly.GetType($"{ConstUtil.After}.Convert.{ConvertName}");
        if (type == null) type = Type.GetType($"CommonLib.Convert.{ConvertName}");
        Convert = Activator.CreateInstance(type!, this) as BaseConvert;
    }

    public string SqlLine()
    {
        return Convert == null ? string.Empty : Convert.SqlLine();
    }

    public List<string> SqlList()
    {
        return Convert == null ? new List<string>() : Convert.SqlList();
    }

    public BaseCodeEntity Enhance()
    {
        CreateRelationShip();
        CreateChain();
        CustomizeEnhance();
        return this;
    }

    protected Dictionary<BaseCodeEntity, ChildrenBean> CreateRelationShip()
    {
        if (ChildrenCode.Count > 0) return ChildrenCode;
        foreach (var prop in GetType().GetProperties())
        {
            var order = prop.GetCustomAttribute<OrderAttribute>();
            if (order == null) continue;
            var obj = prop.GetValue(this);
            if (obj is BaseCodeEntity subCode)
            {
                subCode.ParentEntity = this;
                subCode.CreateRelationShip();
                subCode.CodeIndexLevel = CodeIndexLevel + 1;
                ChildrenCode[subCode] = new ChildrenBean(order.Index, subCode);
            }
            else if (obj is List<BaseCodeEntity> eList)
            {
                foreach (var entity in eList)
                {
                    if (entity is BaseCodeEntity sub)
                    {
                        sub.ParentEntity = this;
                        sub.CreateRelationShip();
                        sub.CodeIndexLevel = CodeIndexLevel + 1;
                        ChildrenCode[sub] = new ChildrenBean(order.Index, sub);
                    }
                }
            }
        }
        return ChildrenCode;
    }

    protected BaseCodeEntity CreateChain()
    {
        var props = GetType().GetProperties().Where(p => p.GetCustomAttribute<OrderAttribute>() != null)
            .OrderBy(p => p.GetCustomAttribute<OrderAttribute>()!.Index).ToList();

        var Current = this;
        foreach (var prop in props)
        {
            var obj = prop.GetValue(this);
            if (obj == null) continue;
            if (obj is BaseCodeEntity entity)
            {
                Current.NextEntity = entity;
                entity.PreEntity = Current;
                Current = entity.CreateChain();
            }
            else if (obj is List<BaseCodeEntity> eList)
            {
                foreach (var eo in eList)
                {
                    if (eo is BaseCodeEntity sub)
                    {
                        Current.NextEntity = sub;
                        sub.PreEntity = Current;
                        Current = sub.CreateChain();
                    }
                }
            }
        }
        return Current;
    }

    protected void CustomizeEnhance()
    {
        ChildrenCode.Values.ToList().ForEach(p => p.CurrentEntity.CustomizeEnhance());
    }

}
